﻿// Copyright (c) Inossem. All rights reserved.
// Licensed under the LGPL-3.0 license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using DWF.Studio.Plugin.Contract;
using DWF.Studio.Plugin.Contract.Enum;
using DWF.Studio.Plugin.Contract.Exceptions;
using DWF.Studio.Plugin.Loader.Config;
using DWF.Studio.Plugin.Loader.Event;
using DWF.Studio.Share.Log;

namespace DWF.Studio.Plugin.Loader
{
    /// <summary>
    /// 主程序域插件加载器
    /// </summary>
    public class PluginMainDomainLoader : PluginLoaderBase
    {
        /// <summary>
        /// 获取信息
        /// </summary>
        /// <param name="pluginConfig"></param>
        /// <returns></returns>
        protected override PluginInfo OnGetInfo(PluginConfig pluginConfig)
        {
            var path = Path.Combine(Path.GetDirectoryName(pluginConfig.Path), pluginConfig.FileName);
            var loadedPluginAssembly = Assembly.LoadFile(path);//加载到当前进程

            Type[] types = loadedPluginAssembly.GetTypes();
            Type pluginBaseType = typeof(PluginBase);//插件基类type

            PluginInfo info = null;
            foreach (Type type in types)
            {
                if (type.IsSubclassOf(pluginBaseType))//判断是否继承插件基类
                {
                    info = new PluginInfo(pluginConfig, type);
                    break;
                }
            }

            return info;
        }

        /// <summary>
        /// 加载
        /// </summary>
        /// <param name="pluginInfo"></param>
        /// <returns></returns>
        protected override PluginBase OnLoad(IPluginInfo pluginInfo)
        {
            if (File.Exists(pluginInfo.AssemblyFileName))//判断文件是否存在
            {
                var loadedPluginAssembly = Assembly.LoadFrom(pluginInfo.AssemblyFileName);//加载到当前程序域

                Type[] types = loadedPluginAssembly.GetTypes();
                Type pluginBaseType = typeof(PluginBase);

                PluginBase plugin = null;
                foreach (Type type in types)
                {
                    if (type.IsSubclassOf(pluginBaseType))
                    {
                        plugin = (PluginBase)Activator.CreateInstance(type, pluginInfo);//创建插件实例
                        this.IsPluginLoaded = true;
                        break;
                    }
                }
                if (plugin != null)
                {
                    return plugin;
                }
                else
                {
                    throw new InvalidPluginFileException(pluginInfo.AssemblyFileName);
                }
            }
            else
            {
                throw new FileNotFoundException("Specified assembly file  does not exist.", pluginInfo.AssemblyFileName);
            }
        }

        /// <summary>
        /// 探测
        /// </summary>
        /// <param name="pluginFolderPath"></param>
        /// <param name="scanDeapth"></param>
        /// <returns></returns>
        protected override PluginInfoList OnProbe(string pluginFolderPath, SearchOption scanDeapth)
        {
            if (!Directory.Exists(pluginFolderPath))
            {
                return null;
            }

            string[] configs = Directory.GetFiles(pluginFolderPath, "plugin.config", SearchOption.AllDirectories);//获取指定目录下得所有配置文件

            List<PluginConfig> pluginConfigs = new List<PluginConfig>();
            foreach (var config in configs)
            {
                try
                {
                    pluginConfigs.Add(PluginConfig.Load(config));//加载所有插件信息 
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }

            var pluginInfos = new PluginInfoList();
            foreach (var file in pluginConfigs)
            {
                try
                {
                    PluginInfo info = this.OnGetInfo(file);
                    if (info != null)
                    {
                        pluginInfos.Add(info);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }

            return pluginInfos;
        }
    }
}
